import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.Socket;
import java.util.Enumeration;
import java.util.Vector;
import java.util.Random;

/**
 * Clase del Juego
 * Clase que funciona con el dealer de nuestro juego de blackjack, 
 * tiene como objetivo aceptar a los jugadores y notificar de las acciones del juego como: 
 * repartir cartas, preguntar por cartas extras y anunciar el fin del juego.
 * @author Mario Valdes, Andres Carmona, Flavio Reyes
 */

public class juegoprueba extends Thread {
	
	  protected Socket s;
	  int jug=0;
	  protected DataInputStream i;
	  protected DataOutputStream o;
	  private 	String Admitir = "Lo sentimos, el juego esta lleno";
	  int jugadores;
	  private 	int	numJugador=3; 
	  int [] sumatoria=new int[5];
	  public boolean hola=true;
	  int [] arregloCartas = new int [5];
	  int [] RealarregloCartas = new int [5];
	  String [] estadoJugador = new String [numJugador];
	  int oso=1;
	  int sumaPuntos=0;
	  
	  
	  BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
/**	   
 * Inicializa los canales de comunicacion para hablar con los clientes (jugadores)
 *  i=para leer
 *  o=para escribir
 */	  
	  public juegoprueba (Socket s) throws IOException {
		    this.s = s;
		    i = new DataInputStream (new BufferedInputStream (s.getInputStream ()));
		    o = new DataOutputStream (new BufferedOutputStream (s.getOutputStream ()));
		  }
		  
	  protected static Vector handlers = new Vector ();
	  
/**	   
 * Metodo principal, de aque parte la comunicacion completa.
 * Paso 1: obtener el nombre del jugador que se conecta y darle aviso a los otros jugadores
 * --NOTA: Si la cantidad de jugadores es igual a 5 (o al total de jugadores por juego)
 * Paso 2: Repartir cartas a los jugadores.
 * Paso 3: Como dealer darme mis cartas
 * Paso 4: Preguntar si los jugadores quieren carta extra.
 * Paso 5: Darme carta extra.
 * Paso 6: Terminar juego y remover jugadores
 * @throws 	  ex.printStackTrace ();
 */
	  public void run () {
		    String name = s.getInetAddress ().getHostName();
		    
		    try {      
		        
			    	o.writeUTF("Jugador"+(handlers.size()+1));
			    	handlers.addElement (this);
			       
			        //NotificarJugadores ("Jugador"+handlers.size());
			        NotificarJugadores (name + " Se ha unido.");
			        System.out.print(name + " Se ha unido."+"\n");
		        
		        
		      if(this==handlers.lastElement()){
		    	while (oso==1) {		    
		    		if(numJugador==handlers.size()){
		    			synchronized(handlers){
			    		  RepartirCartas();
				    	  DarmeCartas();
				    	  PreguntarCarta();
				    	  System.out.print("\n");
				    	  
				    	  for(int ii=0;ii<numJugador;ii++)
				    	  System.out.print(estadoJugador[ii]+"\n");
				    	  
				    	  DarmeCartaExtra();
				    	  
				    	  System.out.print("Final!!!!!!!!"+"\n");
				    	  oso=0;
		    			}
		    			 }
		    		//String line=i.readUTF();
		    	}
		      }
		    }
		    catch (IOException ex) {
		      ex.printStackTrace ();
		    }
		    
		    
		    finally {
		      RemoverJugador();
		    	synchronized(handlers){
		    		try {
						handlers.wait();
						try {
							s.close ();
						} catch (IOException e) {
							// TODO Auto-generated catch block
							e.printStackTrace();
						} 
					} 
		    		catch (InterruptedException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
		    	}
		      NotificarJugadores (name + " has left.");
		      System.out.print(name + " has left." +"\n");
		      try {
		        s.close ();
		      } catch (IOException ex) {
		        ex.printStackTrace();
		      }
		    }
		  }
/**
 * Metodo Preguntar Carta: es decir entregar carta extra si el jugador lo solicita
 * Paso 1: inicializar una comunicacion entre dealer y jugador
 * Paso 2: entrar a un ciclo donde pregunto constantemente al jugador si quiere una
 * nueva carta, de asi serlo llamar metodo CartaExtra(c). De lo contrario salir del 
 * ciclo y guardar el estado del jugador (stand o perdi)
 * @throws	ex.printStackTrace ();
 * @see CartaExtra(c);
 */
	private void PreguntarCarta() throws IOException {
		
		boolean ciclo;
		ciclo=true;
		String hit;
		synchronized (handlers) {
			Enumeration e = handlers.elements ();
			while (e.hasMoreElements ()) {
				juegoprueba c = (juegoprueba) e.nextElement ();
				try {
					synchronized (c.o) {
						while(ciclo==true){
							c.o.writeUTF("pregunta");
							c.o.flush();
							hit = c.i.readUTF();
							System.out.print("la\n");
							System.out.print("------"+hit+"\n");
								if(hit.equals("hitme")){
									CartaExtra(c);
								}
								else{
									ciclo=false;
									estadoJugador[jug]=hit;
									jug++;
								}	
						}
						ciclo=true;
					}
				}
				catch (IOException ex) {
						ex.printStackTrace ();
						c.stop ();
					}
				}
			}

	}

/**
 * Metodo Agregar Jugador: agrega un nuevo jugador al juego
 */
	//@Override
	public void AgregarJugador() {
		// TODO Auto-generated method stub
		handlers.addElement (this);
	}

/**
 * Metodo Broadcast: mandar un mensaje a todos los jugadores del juego
 * @throws	ex.printStackTrace ();
 * @param s Enunciado que notificare a todos lo jugadores
 */
	public void Broadcast(String s) {
		// TODO Auto-generated method stub
		synchronized (handlers) {
	          Enumeration e = handlers.elements ();
	          while (e.hasMoreElements ()) {
	        	  juegoprueba c = (juegoprueba) e.nextElement ();
	            try {
	              synchronized (c.o) {
	                c.o.writeUTF (s);
	              }
	              c.o.flush ();
	            } catch (IOException ex) {
	             c.stop ();
	            }
	          }
	        }
	}

/**
 * Metodo Agregar Jugador: agrega un nuevo jugador al juego
 */
	public void RemoverJugador() {
		// TODO Auto-generated method stub
		handlers.removeElement (this);
	}
    
/**
 * Metodo Repartid Cartas: Reparte un par de cartas a todos los jugadores
 * Las cartas son numeros random del 1 al 52 (total de cartas de la baraja) que el cliente
 * interpreta, por ejemplo:
 * Random rnd = new Random();
		String carta1 = null;
 * 		carta1=String.valueOf(rnd.nextInt(51)+1);
 * Aqui mismo indicamos el turno de cada jugador
 * @throws	ex.printStackTrace ();
 */
	public void RepartirCartas() {
		Random rnd = new Random();
		String carta1 = null;
		String carta2=	null;
		synchronized (handlers) {
	        Enumeration e = handlers.elements ();
	        int x=0;
	        while (e.hasMoreElements ()) {
	        	x++;
	        carta1=String.valueOf(rnd.nextInt(51)+1);
	        carta2=String.valueOf(rnd.nextInt(51)+1);
	        juegoprueba c = (juegoprueba) e.nextElement ();
	          try {
	            synchronized (c.o) {
	              c.o.writeUTF("carta");
	              c.o.writeUTF(carta1);
	              c.o.writeUTF("carta");
	              c.o.writeUTF (carta2);
	            }
	            c.o.flush ();
	          } catch (IOException ex) {
	            c.stop ();
	          }
	          NotificarJugadores("datosJugadoers");
	          NotificarJugadores("Jugador"+x);
	          NotificarJugadores(""+carta2);
	          
	        }
	      }
		NotificarJugadores("Ahi tan sus cartas");
    }
  
/**
 * Metodo Darme Cartas: aqui el dealer se reparte sus primeras dos cartas
 * Las cartas son numeros random del 1 al 52 (total de cartas de la baraja) que el cliente
 * interpreta, por ejemplo:
 * Random rndServer = new Random();
    	arregloCartas[0]=rndServer.nextInt(51)+1;
 * Al final notifico al los jugadores las cartas del dealer
 * @throws	ex.printStackTrace ();
 */
    public void DarmeCartas() {
    	Random rndServer = new Random();
    	arregloCartas[0]=rndServer.nextInt(51)+1;
    	arregloCartas[1]=rndServer.nextInt(51)+1;
    	for(int i=2;i<5;i++)
    	arregloCartas[i]=0;
    	
    	NotificarJugadores("Dealer");
    	NotificarJugadores(String.valueOf(arregloCartas[0]));
    }
    
/**
 * 
 * @param c Instancia del juego
 */
    public void CartaExtra(juegoprueba c) {
    	Random rnd = new Random();
		String cartaext = null;
		cartaext=String.valueOf(rnd.nextInt(51)+1);
		try {
			//c.o.writeUTF("carta");
			c.o.writeUTF(cartaext);
			c.o.flush ();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
    }
    
    public void DarmeCartaExtra() {
    	TraducirCartas tc=new TraducirCartas();
    	
    	RealarregloCartas[0]=tc.Transformar(arregloCartas[0]);
    	RealarregloCartas[1]=tc.Transformar(arregloCartas[1]);
    	
    	sumatoria();
    	
    	for(int yy=2;yy<5;yy++){
    		RealarregloCartas[yy]=0;
    	}
    	//(RealarregloCartas[0]+RealarregloCartas[1]+RealarregloCartas[2]+RealarregloCartas[3]+RealarregloCartas[4]);
    	int i=2;
    	sumatoria();
    	Random rndServer = new Random();
    	System.out.print("Mi sumatoria Total es: "+sumaPuntos+"\n");
    	while(sumaPuntos<17){
    		arregloCartas[i]=rndServer.nextInt(51)+1;
    		
    		RealarregloCartas[i]=tc.Transformar(arregloCartas[i]);
    		sumatoria();
    		i++;
    	}
    	if(sumaPuntos>=17)
    		System.out.print("Mi sumatoria Total es: "+sumaPuntos+"\n");
    	notificarDealer();
    	NotificarJugadores("final");
    	NotificarJugadores(String.valueOf((sumaPuntos)));
    }
    
    public void notificarDealer(){
    	
    	NotificarJugadores("DealerFinal");
    	
    	for(int i=0;i<5;i++){
    		NotificarJugadores(String.valueOf(arregloCartas[i]));
    	}
    }
    
    public void VoltearCartas() {
    
    }
    
    public void RepartirDinero() {
    
    }
    
    public void GanarPerder() {
    
    }
    
    public void LevantarConexion() {
    
    }
    
    public void NotificarSolo() {
        
    }
    
    public void NoAdmitir(String msg) {
        try {
			o.writeUTF(msg);
			RemoverJugador();
			//s.close ();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
    }

	//@Override
	public void NotificarJugadores(String s) {
	    synchronized (handlers) {
	        Enumeration e = handlers.elements ();
	        while (e.hasMoreElements ()) {
	        	juegoprueba c = (juegoprueba) e.nextElement ();
	          try {
	            synchronized (c.o) {
	              c.o.writeUTF (s);
	            }
	            c.o.flush ();
	          } catch (IOException ex) {
	            c.stop ();
	          }
	        }
	      }
	    }
	
    public void sumatoria(){
    	
    	int sum=0;
    	
    	for(int i=0;i<5;i++){
    		if((RealarregloCartas[i]==111)&& (sumaPuntos<11))
    			RealarregloCartas[i]=11;
    		if((RealarregloCartas[i]==111)&& (sumaPuntos>11)) 
    			RealarregloCartas[i]=1;
    			
    		sum=sum+RealarregloCartas[i];	
    	}
    	sumaPuntos=sum;
    	
    }
}
